
(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['jquery'], function ($) {
      return (root.returnExportsGlobal = factory($));
    });
  } else if (typeof exports === 'object') {
    // Node. Does not work with strict CommonJS, but
    // only CommonJS-like enviroments that support module.exports,
    // like Node.
    module.exports = factory(require('jquery'));
  } else {
    factory(jQuery);
  }
}(this, function ($) {

  /*
  Implement Github like autocomplete mentions
  http://ichord.github.com/At.js

  Copyright (c) 2013 chord.luo@gmail.com
  Licensed under the MIT license.
*/

  /*
本插件操作 textarea 或者 input 内的插入符
只实现了获得插入符在文本框中的位置，我设置
插入符的位置.
*/

  'use strict';
  let EditableCaret,
    InputCaret,
    Mirror,
    Utils,
    discoveryIframeOf,
    methods,
    oDocument,
    oFrame,
    oWindow,
    pluginName,
    setContextBy;

  pluginName = 'caret';

  EditableCaret = (function () {
    function EditableCaret($inputor) {
      this.$inputor = $inputor;
      this.domInputor = this.$inputor[0];
    }

    EditableCaret.prototype.setPos = function (pos) {
      let fn,
        found,
        offset,
        sel;
      if (sel = oWindow.getSelection()) {
        offset = 0;
        found = false;
        (fn = function (pos, parent) {
          let node,
            range,
            _i,
            _len,
            _ref,
            _results;
          _ref = parent.childNodes;
          _results = [];
          for (_i = 0, _len = _ref.length; _i < _len; _i++) {
            node = _ref[_i];
            if (found) {
              break;
            }
            if (node.nodeType === 3) {
              if (offset + node.length >= pos) {
                found = true;
                range = oDocument.createRange();
                range.setStart(node, pos - offset);
                sel.removeAllRanges();
                sel.addRange(range);
                break;
              } else {
                _results.push(offset += node.length);
              }
            } else {
              _results.push(fn(pos, node));
            }
          }
          return _results;
        })(pos, this.domInputor);
      }
      return this.domInputor;
    };

    EditableCaret.prototype.getIEPosition = function () {
      return this.getPosition();
    };

    EditableCaret.prototype.getPosition = function () {
      let inputor_offset,
        offset;
      offset = this.getOffset();
      inputor_offset = this.$inputor.offset();
      offset.left -= inputor_offset.left;
      offset.top -= inputor_offset.top;
      return offset;
    };

    EditableCaret.prototype.getOldIEPos = function () {
      let preCaretTextRange,
        textRange;
      textRange = oDocument.selection.createRange();
      preCaretTextRange = oDocument.body.createTextRange();
      preCaretTextRange.moveToElementText(this.domInputor);
      preCaretTextRange.setEndPoint('EndToEnd', textRange);
      return preCaretTextRange.text.length;
    };

    EditableCaret.prototype.getPos = function () {
      let clonedRange,
        pos,
        range;
      if (range = this.range()) {
        clonedRange = range.cloneRange();
        clonedRange.selectNodeContents(this.domInputor);
        clonedRange.setEnd(range.endContainer, range.endOffset);
        pos = clonedRange.toString().length;
        clonedRange.detach();
        return pos;
      } else if (oDocument.selection) {
        return this.getOldIEPos();
      }
    };

    EditableCaret.prototype.getOldIEOffset = function () {
      let range,
        rect;
      range = oDocument.selection.createRange().duplicate();
      range.moveStart('character', -1);
      rect = range.getBoundingClientRect();
      return {
        height: rect.bottom - rect.top,
        left: rect.left,
        top: rect.top,
      };
    };

    EditableCaret.prototype.getOffset = function (pos) {
      let clonedRange,
        offset,
        range,
        rect,
        shadowCaret;
      if (oWindow.getSelection && (range = this.range())) {
        if (range.endOffset - 1 > 0 && range.endContainer !== this.domInputor) {
          clonedRange = range.cloneRange();
          clonedRange.setStart(range.endContainer, range.endOffset - 1);
          clonedRange.setEnd(range.endContainer, range.endOffset);
          rect = clonedRange.getBoundingClientRect();
          offset = {
            height: rect.height,
            left: rect.left + rect.width,
            top: rect.top,
          };
          clonedRange.detach();
        }
        if (!offset || (offset != null ? offset.height : void 0) === 0) {
          clonedRange = range.cloneRange();
          shadowCaret = $(oDocument.createTextNode('|'));
          clonedRange.insertNode(shadowCaret[0]);
          clonedRange.selectNode(shadowCaret[0]);
          rect = clonedRange.getBoundingClientRect();
          offset = {
            height: rect.height,
            left: rect.left,
            top: rect.top,
          };
          shadowCaret.remove();
          clonedRange.detach();
        }
      } else if (oDocument.selection) {
        offset = this.getOldIEOffset();
      }
      if (offset) {
        offset.top += $(oWindow).scrollTop();
        offset.left += $(oWindow).scrollLeft();
      }
      return offset;
    };

    EditableCaret.prototype.range = function () {
      let sel;
      if (!oWindow.getSelection) {
        return;
      }
      sel = oWindow.getSelection();
      if (sel.rangeCount > 0) {
        return sel.getRangeAt(0);
      }
      return null;

    };

    return EditableCaret;

  })();

  InputCaret = (function () {
    function InputCaret($inputor) {
      this.$inputor = $inputor;
      this.domInputor = this.$inputor[0];
    }

    InputCaret.prototype.getIEPos = function () {
      let endRange,
        inputor,
        len,
        normalizedValue,
        pos,
        range,
        textInputRange;
      inputor = this.domInputor;
      range = oDocument.selection.createRange();
      pos = 0;
      if (range && range.parentElement() === inputor) {
        normalizedValue = inputor.value.replace(/\r\n/g, '\n');
        len = normalizedValue.length;
        textInputRange = inputor.createTextRange();
        textInputRange.moveToBookmark(range.getBookmark());
        endRange = inputor.createTextRange();
        endRange.collapse(false);
        if (textInputRange.compareEndPoints('StartToEnd', endRange) > -1) {
          pos = len;
        } else {
          pos = -textInputRange.moveStart('character', -len);
        }
      }
      return pos;
    };

    InputCaret.prototype.getPos = function () {
      if (oDocument.selection) {
        return this.getIEPos();
      }
      return this.domInputor.selectionStart;

    };

    InputCaret.prototype.setPos = function (pos) {
      let inputor,
        range;
      inputor = this.domInputor;
      if (oDocument.selection) {
        range = inputor.createTextRange();
        range.move('character', pos);
        range.select();
      } else if (inputor.setSelectionRange) {
        inputor.setSelectionRange(pos, pos);
      }
      return inputor;
    };

    InputCaret.prototype.getIEOffset = function (pos) {
      let h,
        textRange,
        x,
        y;
      textRange = this.domInputor.createTextRange();
      pos || (pos = this.getPos());
      textRange.move('character', pos);
      x = textRange.boundingLeft;
      y = textRange.boundingTop;
      h = textRange.boundingHeight;
      return {
        left: x,
        top: y,
        height: h,
      };
    };

    InputCaret.prototype.getOffset = function (pos) {
      let $inputor,
        offset,
        position;
      $inputor = this.$inputor;
      if (oDocument.selection) {
        offset = this.getIEOffset(pos);
        offset.top += $(oWindow).scrollTop() + $inputor.scrollTop();
        offset.left += $(oWindow).scrollLeft() + $inputor.scrollLeft();
        return offset;
      }
      offset = $inputor.offset();
      position = this.getPosition(pos);
      return offset = {
        left: offset.left + position.left - $inputor.scrollLeft(),
        top: offset.top + position.top - $inputor.scrollTop(),
        height: position.height,
      };

    };

    InputCaret.prototype.getPosition = function (pos) {
      let $inputor,
        at_rect,
        end_range,
        format,
        html,
        mirror,
        start_range;
      $inputor = this.$inputor;
      format = function (value) {
        value = value.replace(/<|>|`|"|&/g, '?').replace(/\r\n|\r|\n/g, '<br/>');
        if (/firefox/i.test(navigator.userAgent)) {
          value = value.replace(/\s/g, '&nbsp;');
        }
        return value;
      };
      if (pos === void 0) {
        pos = this.getPos();
      }
      start_range = $inputor.val().slice(0, pos);
      end_range = $inputor.val().slice(pos);
      html = "<span style='position: relative; display: inline;'>" + format(start_range) + '</span>';
      html += "<span id='caret' style='position: relative; display: inline;'>|</span>";
      html += "<span style='position: relative; display: inline;'>" + format(end_range) + '</span>';
      mirror = new Mirror($inputor);
      return at_rect = mirror.create(html).rect();
    };

    InputCaret.prototype.getIEPosition = function (pos) {
      let h,
        inputorOffset,
        offset,
        x,
        y;
      offset = this.getIEOffset(pos);
      inputorOffset = this.$inputor.offset();
      x = offset.left - inputorOffset.left;
      y = offset.top - inputorOffset.top;
      h = offset.height;
      return {
        left: x,
        top: y,
        height: h,
      };
    };

    return InputCaret;

  })();

  Mirror = (function () {
    Mirror.prototype.css_attr = ['borderBottomWidth', 'borderLeftWidth', 'borderRightWidth', 'borderTopStyle', 'borderRightStyle', 'borderBottomStyle', 'borderLeftStyle', 'borderTopWidth', 'boxSizing', 'fontFamily', 'fontSize', 'fontWeight', 'height', 'letterSpacing', 'lineHeight', 'marginBottom', 'marginLeft', 'marginRight', 'marginTop', 'outlineWidth', 'overflow', 'overflowX', 'overflowY', 'paddingBottom', 'paddingLeft', 'paddingRight', 'paddingTop', 'textAlign', 'textOverflow', 'textTransform', 'whiteSpace', 'wordBreak', 'wordWrap'];

    function Mirror($inputor) {
      this.$inputor = $inputor;
    }

    Mirror.prototype.mirrorCss = function () {
      let css,
        _this = this;
      css = {
        position: 'absolute',
        left: -9999,
        top: 0,
        zIndex: -20000,
      };
      if (this.$inputor.prop('tagName') === 'TEXTAREA') {
        this.css_attr.push('width');
      }
      $.each(this.css_attr, function (i, p) {
        return css[p] = _this.$inputor.css(p);
      });
      return css;
    };

    Mirror.prototype.create = function (html) {
      this.$mirror = $('<div></div>');
      this.$mirror.css(this.mirrorCss());
      this.$mirror.html(html);
      this.$inputor.after(this.$mirror);
      return this;
    };

    Mirror.prototype.rect = function () {
      let $flag,
        pos,
        rect;
      $flag = this.$mirror.find('#caret');
      pos = $flag.position();
      rect = {
        left: pos.left,
        top: pos.top,
        height: $flag.height(),
      };
      this.$mirror.remove();
      return rect;
    };

    return Mirror;

  })();

  Utils = {
    contentEditable($inputor) {
      return !!($inputor[0].contentEditable && $inputor[0].contentEditable === 'true');
    },
  };

  methods = {
    pos(pos) {
      if (pos || pos === 0) {
        return this.setPos(pos);
      }
      return this.getPos();

    },
    position(pos) {
      if (oDocument.selection) {
        return this.getIEPosition(pos);
      }
      return this.getPosition(pos);

    },
    offset(pos) {
      let offset;
      offset = this.getOffset(pos);
      return offset;
    },
  };

  oDocument = null;

  oWindow = null;

  oFrame = null;

  setContextBy = function (settings) {
    let iframe;
    if (iframe = settings != null ? settings.iframe : void 0) {
      oFrame = iframe;
      oWindow = iframe.contentWindow;
      return oDocument = iframe.contentDocument || oWindow.document;
    }
    oFrame = void 0;
    oWindow = window;
    return oDocument = document;

  };

  discoveryIframeOf = function ($dom) {
    let error;
    oDocument = $dom[0].ownerDocument;
    oWindow = oDocument.defaultView || oDocument.parentWindow;
    try {
      return oFrame = oWindow.frameElement;
    } catch (_error) {
      error = _error;
    }
  };

  $.fn.caret = function (method, value, settings) {
    let caret;
    if (methods[method]) {
      if ($.isPlainObject(value)) {
        setContextBy(value);
        value = void 0;
      } else {
        setContextBy(settings);
      }
      caret = Utils.contentEditable(this) ? new EditableCaret(this) : new InputCaret(this);
      return methods[method].apply(caret, [value]);
    }
    return $.error('Method ' + method + ' does not exist on jQuery.caret');

  };

  $.fn.caret.EditableCaret = EditableCaret;

  $.fn.caret.InputCaret = InputCaret;

  $.fn.caret.Utils = Utils;

  $.fn.caret.apis = methods;


}));
